package com.malamute.core.interceptor;

import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import com.malamute.core.exception.BusinessException;
import com.malamute.core.exception.DatabaseException;
import com.malamute.core.exception.SystemException;
import com.malamute.system.entity.Log;
import com.malamute.system.service.LogService;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.config.entities.ExceptionMappingConfig;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

/**
 * 系统异常拦截器
 * 
 */
public class SystemExceptionInterceptor extends AbstractInterceptor {
	Logger log = Logger.getLogger(SystemExceptionInterceptor.class);

	@Autowired(required = false)
	private LogService logService;

	@Override
	public String intercept(ActionInvocation actionInvocation) throws Exception {
		String result = null;
		try {
			result = actionInvocation.invoke();
		} catch (SystemException e) {
			log.info("发生异常：SystemExceptionInterceptor+++++++++++++++++++");
			e.printStackTrace();
			Log log = new Log();
			log.setClassName(actionInvocation.getAction().getClass().getName());
			log.setMethodName("actionName:"
					+ actionInvocation.getInvocationContext().getName());
			log.setErrorMessage(e.getMessage());
			log.setExceptionName(e.getClass().getName());
			logService.saveLog(log);

			List<ExceptionMappingConfig> exceptionMappings = actionInvocation
					.getProxy().getConfig().getExceptionMappings();
			String mappedResult = this.findResultFromExceptions(
					exceptionMappings, e);
			if (mappedResult != null) {
				result = mappedResult;
			}
			if (e instanceof BusinessException) {
				// 业务异常

			} else if (e instanceof DatabaseException) {
				// 数据库异常

			} else {
				throw e;
			}
		}
		return result;
	}

	protected String findResultFromExceptions(
			List<ExceptionMappingConfig> exceptionMappings, Throwable t) {
		String result = null;

		// Check for specific exception mappings.
		if (exceptionMappings != null) {
			int deepest = Integer.MAX_VALUE;
			for (Object exceptionMapping : exceptionMappings) {
				ExceptionMappingConfig exceptionMappingConfig = (ExceptionMappingConfig) exceptionMapping;
				int depth = getDepth(
						exceptionMappingConfig.getExceptionClassName(), t);
				if (depth >= 0 && depth < deepest) {
					deepest = depth;
					result = exceptionMappingConfig.getResult();
				}
			}
		}

		return result;
	}

	/**
	 * Return the depth to the superclass matching. 0 means ex matches exactly.
	 * Returns -1 if there's no match. Otherwise, returns depth. Lowest depth
	 * wins.
	 * 
	 * @param exceptionMapping
	 *            the mapping classname
	 * @param t
	 *            the cause
	 * @return the depth, if not found -1 is returned.
	 */
	public int getDepth(String exceptionMapping, Throwable t) {
		return getDepth(exceptionMapping, t.getClass(), 0);
	}

	private int getDepth(String exceptionMapping, Class exceptionClass,
			int depth) {
		if (exceptionClass.getName().contains(exceptionMapping)) {
			// Found it!
			return depth;
		}
		// If we've gone as far as we can go and haven't found it...
		if (exceptionClass.equals(Throwable.class)) {
			return -1;
		}
		return getDepth(exceptionMapping, exceptionClass.getSuperclass(),
				depth + 1);
	}
}
